import os
import zipfile
import plistlib
from flask import Flask, request, render_template, send_from_directory, jsonify

app = Flask(__name__)

# 全局配置
UPLOAD_FOLDER = './uploads'
MANIFEST_FOLDER = './manifests'
MAX_CONTENT_LENGTH = 200 * 1024 * 1024  # 200MB
DOMAIN = "https://www.wangyetech.com"
PORT = "8000"

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MANIFEST_FOLDER'] = MANIFEST_FOLDER
app.config['MAX_CONTENT_LENGTH'] = MAX_CONTENT_LENGTH

# 确保文件夹存在
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(MANIFEST_FOLDER, exist_ok=True)

# 解析 IPA 文件
def parse_ipa(file_path):
    try:
        print(f"解析 IPA 文件: {file_path}")

        # 打开 IPA 文件作为 ZIP 压缩包
        with zipfile.ZipFile(file_path, 'r') as z:
            # 确定主应用 Info.plist 的路径
            main_info_plist_path = "Payload/Runner.app/Info.plist"

            if main_info_plist_path not in z.namelist():
                raise FileNotFoundError(f"{main_info_plist_path} not found in the .ipa file!")

            # 打开主应用的 Info.plist
            print(f"Located main Info.plist at: {main_info_plist_path}")
            with z.open(main_info_plist_path) as plist_file:
                # 读取文件内容为二进制数据
                plist_data_binary = plist_file.read()
                # 使用 plistlib.loads 解析二进制数据
                plist_data = plistlib.loads(plist_data_binary)

            print("plist_data: ")
            print(plist_data)

            # 提取必要的信息
            bundle_id = plist_data.get('CFBundleIdentifier')
            version = plist_data.get('CFBundleShortVersionString')
            app_name = plist_data.get('CFBundleName') or plist_data.get('CFBundleDisplayName')

            return {
                'bundle_id': bundle_id,
                'version': version,
                'app_name': app_name
            }

    except zipfile.BadZipFile:
        raise ValueError("Uploaded file is not a valid .ipa (ZIP) archive")
    except Exception as e:
        raise ValueError(f"Error parsing IPA: {str(e)}")

# 生成 manifest.plist
def generate_manifest(ipa_url, app_info, manifest_path):
    manifest_template = {
        "items": [
            {
                "assets": [
                    {
                        "kind": "software-package",
                        "url": f"{DOMAIN}:{PORT}{ipa_url}"
                    }
                ],
                "metadata": {
                    "bundle-identifier": app_info['bundle_id'],
                    "bundle-version": app_info['version'],
                    "kind": "software",
                    "title": app_info['app_name']
                }
            }
        ]
    }
    with open(manifest_path, 'wb') as f:
        plistlib.dump(manifest_template, f)

# 上传页面
@app.route('/')
def upload_page():
    return render_template('upload.html')

# 下载页面
@app.route('/download')
def download_page():
    # 获取 manifests 文件夹中的 .plist 文件列表
    manifests = [f for f in os.listdir(MANIFEST_FOLDER) if f.endswith('.plist')]
    apps = []
    for manifest in manifests:
        manifest_path = os.path.join(MANIFEST_FOLDER, manifest)
        with open(manifest_path, 'rb') as f:
            plist_data = plistlib.load(f)
            app_info = plist_data['items'][0]['metadata']
            apps.append({
                'app_name': app_info['title'],
                'manifest_url': f"{DOMAIN}:{PORT}/manifests/{manifest}"
            })
    return render_template('download.html', apps=apps)

# 上传文件处理
@app.route('/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return jsonify({"error": "No file part"}), 400

    file = request.files['file']
    if file.filename == '':
        return jsonify({"error": "No selected file"}), 400

    if not file.filename.endswith('.ipa'):
        return jsonify({"error": "File must be a .ipa"}), 400

    # 保存文件到磁盘
    ipa_path = os.path.join(UPLOAD_FOLDER, file.filename)
    file.save(ipa_path)

    # 检查文件是否正确保存
    if not os.path.exists(ipa_path):
        return jsonify({"error": "File not saved"}), 500

    file_size = os.path.getsize(ipa_path)
    print(f"Saved IPA file at: {ipa_path}, Size: {file_size} bytes")

    # 验证文件头部是否为 ZIP 格式
    with open(ipa_path, 'rb') as f:
        header = f.read(4)
    print(f"File header: {header}")
    if header != b'PK\x03\x04':  # ZIP 文件的标志头
        return jsonify({"error": "Uploaded file is not a valid ZIP archive"}), 400

    # 解析 IPA 文件
    try:
        app_info = parse_ipa(ipa_path)
        print("Parsed app info:", app_info)
    except Exception as e:
        print(f"Error during parsing: {e}")
        return jsonify({"error": f"Error parsing IPA: {e}"}), 400

    # 生成 manifest.plist
    manifest_filename = f"{app_info['bundle_id']}.plist"
    manifest_path = os.path.join(MANIFEST_FOLDER, manifest_filename)
    ipa_url = f"/uploads/{file.filename}"
    generate_manifest(ipa_url, app_info, manifest_path)

    # 返回成功响应
    redirect_url = "/download"
    return jsonify({"message": "Upload successful", "redirect_url": redirect_url})

# 调试进度接口（可选）
@app.route('/progress')
def progress():
    return jsonify({"status": "success"})

# manifests静态访问
@app.route('/manifests/<path:filename>')
def download_manifest(filename):
    return send_from_directory(MANIFEST_FOLDER, filename)

# uploads静态访问
@app.route('/uploads/<path:filename>')
def download_ipa(filename):
    return send_from_directory(UPLOAD_FOLDER, filename)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(PORT), ssl_context=(
        '/etc/letsencrypt/live/wangyetech.com/fullchain.pem',
        '/etc/letsencrypt/live/wangyetech.com/privkey.pem'
    ))

